/******************************************************************************

  Copyright (C), 2012-2016, ZHANGYA

 ******************************************************************************
  File Name     : uaprot.c
  Version       : Initial Draft
  Author        : zhangya
  Created       : 2024/5/7
  Last Modified :
  Description   : uaprot.c
  Function List :
  History       :
  1.Date        : 2024/5/7
    Author      : zhangya
    Modification: Created file

******************************************************************************/
#include "uaprot.h"

/*--------------------------------------------------------------------*
 * $external variables                           *
 *--------------------------------------------------------------------*/
const uint16_t ycalc_crc16_tblst[0x100] = {
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

#define XDPACK_XFCS_LENGTH              (0x0002)
#define XDPACK_HEAD_LENGTH              (0x0008)
#define XDPACK_SFCS_LENGTH              (0x0006)

#define XDPACK_MSGID_LOCATION           (0x02)

#define XDPACK_HEAD_XCHR                (0x7E)
#define XDPACK_HEAD_XTAG                (0x5A)
#define XDPACK_HEAD_XKHD                (0x5A7E)
#define XDPACK_INIT_XFCS                (0xFFFF)

/*--------------------------------------------------------------------*
 * $external routine prototypes                  *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $internal routine prototypes                  *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $project-wide global variables                *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $module-wide global variables                 *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $constants                                    *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $macros                                       *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $routines' implementations                    *
 *--------------------------------------------------------------------*/

static uint16_t get_crc16_byte(uint16_t initcrc, uint8_t kval)
{
    return ((initcrc) << 8) ^ ycalc_crc16_tblst[((uint8_t)(kval ^ (initcrc >> 8)))];
}

static uint16_t get_crc16(const void *xfer, int len, uint16_t initcrc)
{
    for (int item=0; item<len; item++)
	{
        initcrc = get_crc16_byte(initcrc, ((uint8_t*)(xfer))[item]);
    }

    return initcrc;
}

inline uint16_t combo_word(const uint8_t * buff)
{
	uint16_t temp = buff[1];
	return ((temp << 8) & 0xff00) | buff[0];
}

inline void parse_word(uint8_t * buff, uint16_t word)
{
	buff[0] = (word & 0xff);
	buff[1] = (word >> 8) & 0xff;
}

inline uint32_t combo_dword(const uint8_t * buff)
{
	uint32_t temp = buff[3];
	for (int i=2; i>=0; i--)
		temp = (temp << 8) | buff[i];
	return temp;
}

inline void parse_dword(uint8_t * buff, uint32_t dword)
{
	buff[0] = (dword & 0xff);
	buff[1] = (dword >> 8) & 0xff;
	buff[2] = (dword >> 16) & 0xff;
	buff[3] = (dword >> 24) & 0xff;
}

/*****************************************************************************
 Prototype    : uaprot_package
 Description  : uaprot package
 Input        : const pack_para_t * para  
                uint8_t * buff            
                uint16_t size             
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
int uaprot_package(const pack_para_t * para, uint8_t * buff, uint16_t size)
{
	if (para == NULL || buff  == NULL || size == 0)
	{
		DEBUG_STR("package para err\r\n");
		return 0;
	}

	if (size < para->dlen + 11)
	{
		DEBUG_STR("buff size is err\r\n");
		return 0;
	}

	int index = 0;
	buff[index++] = XDPACK_HEAD_XCHR;
	buff[index++] = XDPACK_HEAD_XTAG;
	buff[index++] = para->msgid;
	buff[index++] = para->bctl;
	buff[index++] = para->port;
	buff[index++] = (uint8_t)(para->dlen & 0xff);
	uint16_t crc = get_crc16(&buff[0], index, XDPACK_INIT_XFCS);
	buff[index++] = (crc >> 8) & 0xff;
	buff[index++] = crc & 0xff;
	if (para->dlen != 0)
	{
		memcpy(&buff[index], para->pdata, para->dlen);
		index += para->dlen;
	}
	crc = get_crc16(&buff[0], index, XDPACK_INIT_XFCS);
	buff[index++] = (crc >> 8) & 0xff;
	buff[index++] = crc & 0xff;
	buff[index++] = 0xA5;

	return index;
}
/*****************************************************************************
 Prototype    : uaprot_control_adjust
 Description  : uaprot control adjust
 Input        : uint16_t bits        
                const uint8_t * dat  
                uint16_t dlen        
                pack_para_t * para   
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
bool uaprot_control_adjust(const uint8_t * dat, uint16_t dlen, pack_para_t * para)
{
	if (para == NULL) {
		DEBUG_STR("uaprot_control_adjust:para==null");
		return false;
	}

	uint16_t bits = combo_word(dat);
	para->bctl = KEYID_BCTL_ADJUST;
	para->port = 0;
	para->pdata = NULL;

	if (bits == DIRTY_READ){
		para->dlen = 0;
		return true;
	}
	if (bits == DIRTY_TOTAL)
	{
		para->dlen = dlen;
		para->pdata = (uint8_t *)dat;
		return true;
	}

	static uint8_t buff[32];
	memset(buff, 0, sizeof(buff));
	para->pdata = buff;

	uint8_t buf_index = 0;
	uint8_t dat_index = 0;

	memcpy(&buff[buf_index], dat, 2);
	buf_index += 2;
	dat_index += 2;
	if (KGET_BITS_DIRTY(bits, DIRTY_BRIGHTNESS) && dlen >= dat_index + 1)
	{
		buff[buf_index++] = dat[dat_index++];
	}else{
		buff[buf_index++] = 0;
	}

	if (KGET_BITS_DIRTY(bits, DIRTY_CONTRAST) && dlen >= dat_index + 1)
    {
        buff[buf_index++] = dat[dat_index++];
    }else{
        buff[buf_index++] = 0;
    }

    if (KGET_BITS_DIRTY(bits, DIRTY_HUE) && dlen >= dat_index + 1)
    {
        buff[buf_index++] = dat[dat_index++];
    }else{
        buff[buf_index++] = 0;
    }

    if (KGET_BITS_DIRTY(bits, DIRTY_SATURATION) && dlen >= dat_index + 1)
    {
        buff[buf_index++] = dat[dat_index++];
    }else{
        buff[buf_index++] = 0;
    }

    if (KGET_BITS_DIRTY(bits, DIRTY_SHARPNESS) && dlen >= dat_index + 1)
    {
        buff[buf_index++] = dat[dat_index++];
    }else{
        buff[buf_index++] = 0;
    }

    if (KGET_BITS_DIRTY(bits, DIRTY_DENOISE) && dlen >= dat_index + 1)
    {
        buff[buf_index++] = dat[dat_index++];
    }else{
        buff[buf_index++] = 0;
    }

    if (KGET_BITS_DIRTY(bits, DIRTY_GAIN) && dlen >= dat_index + 8)
    {
		memcpy(&buff[buf_index], &dat[dat_index], 8);
        buf_index += 8;
		dat_index += 8;
    }else{
		memset(&buff[buf_index], 0, 8);
        buf_index += 8;
    }

    if (KGET_BITS_DIRTY(bits, DIRTY_GFE_CLASS) && dlen >= dat_index + 8)
    {
		memcpy(&buff[buf_index], &dat[dat_index], 8);
        buf_index += 8;
		dat_index += 8;
    }else{
		memset(&buff[buf_index], 0, 8);
        buf_index += 8;
    }
	para->dlen = (uint8_t)buf_index;

	//DEBUG_BUF_U8("AA=", buff, buf_index);

	return true;
}

/*****************************************************************************
 Prototype    : uaprot_unpack_one
 Description  : uaprot unpack on
 Input        : pack_para_t * para  
                const int16_t data  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
bool uaprot_unpack_one(pack_para_t * para, const int16_t data)
{
	if (para == NULL || para->pdata == NULL)
	{
		DEBUG_STR("uaprot unpackage para err");
		return false;
	}

	static int index = 0;
	static int dindex = 0;
	static uint16_t crc = XDPACK_INIT_XFCS;
	static uint16_t crcTemp = 0;

	if (data < 0)
	{
		index = 0;
		dindex = 0;
		crc = XDPACK_INIT_XFCS;
		crcTemp = 0;
		return false;
	}

	if (data == XDPACK_HEAD_XCHR && index == 0)  //0x7E
	{
		index++;
		crc = get_crc16_byte(crc, data);
	}
	else if (data == XDPACK_HEAD_XTAG && index == 1) // 0x5A
	{
		index++;
		crc = get_crc16_byte(crc, data);
	}
	else if (index == 2) //msgid
	{
		index++;
		crc = get_crc16_byte(crc, data);
		para->msgid = data;
	}
	else if (index == 3) //bctl
	{
		index++;
		crc = get_crc16_byte(crc, data);
		para->bctl = data;
	}
	else if (index == 4) //port
	{
		index++;
		crc = get_crc16_byte(crc, data);
		para->port = data;
	}
	else if (index == 5) //dlen
	{
		index++;
		crc = get_crc16_byte(crc, data);
		crcTemp = crc;
		para->dlen = data;
	}
	else if ((data == ((crcTemp >> 8) & 0xff)) && (index == 6))
	{
		index++;
		crc = get_crc16_byte(crc, data);
	}
	else if ((data == (crcTemp & 0xff)) && (index == 7))
	{
		index++;
		crc = get_crc16_byte(crc, data);
		crcTemp = crc;
	}
	else if ((index > 7) && (index < (8 + para->dlen)))
	{
		index++;
		crc = get_crc16_byte(crc, data);
		crcTemp = crc;
		para->pdata[dindex++] = data;
	}
	else if ((data == ((crcTemp >> 8) & 0xff)) && (index == (8 + para->dlen)))
	{
		index++;
	}
	else if ((data == (crcTemp & 0xff)) && (index == (9 + para->dlen)))
	{
		index = 0;
		dindex = 0;
		crc = XDPACK_INIT_XFCS;
		crcTemp = 0;

		return true;
	}else{
		DEBUG_INFO("uaprot unpack in=%d, di=%d", index, dindex);
		index = 0;
		dindex = 0;
		crc = XDPACK_INIT_XFCS;
		crcTemp = 0;

		return false;
	}

	return false;
}

/*****************************************************************************
 Prototype    : uaprot_find
 Description  : uaprot find
 Input        : const uint8_t * pack  
                const uint16_t len    
                uint8_t * msgid       
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
int uaprot_find(const uint8_t * pack, const uint16_t len, uint8_t * msgid)
{
	if (pack == NULL || len == 0 || msgid == NULL)
	{
		DEBUG_STR("uaprot find para err\r\n");
		return -1;
	}

	for (int i=0; i<len-2; i++)
	{
		if (pack[i] == XDPACK_HEAD_XCHR &&
			pack[i+1] == XDPACK_HEAD_XTAG)
		{
			if (len - i < XDPACK_HEAD_LENGTH)
				return -1;
			*msgid = pack[i+2];
			return i;
		}
	}
	return -1;
}

/*****************************************************************************
 Prototype    : uaprot_unpack
 Description  : uaprot unpack
 Input        : pack_para_t * para    
                const uint8_t * pack  
                const uint16_t len    
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
int uaprot_unpack(pack_para_t * para, const uint8_t * pack, const uint16_t len)
{
	if (para == NULL || pack == NULL || len == 0)
	{
		DEBUG_STR("uaprot check para err\r\n");
		return 0;
	}
	int index = 3;
	uint8_t bctl = pack[index++];
	uint8_t port = pack[index++];
	uint8_t dlen = pack[index++];

	uint16_t crc = get_crc16(&pack[0], XDPACK_SFCS_LENGTH, XDPACK_INIT_XFCS);
	if (((crc >> 8) & 0xff) != pack[index++] ||
		((crc & 0xff) != pack[index++]))
	{
		DEBUG_STR("uaprot check crc1 err\r\n");
		return 0;
	}
	if (para->pdata == NULL)
	{
		DEBUG_STR("uaprot check para->pdata err\r\n");
		return 0;
	}
	memcpy(para->pdata, &pack[index], dlen);
	index += dlen;
	crc = get_crc16(&pack[0], dlen + XDPACK_HEAD_LENGTH, XDPACK_INIT_XFCS);
	if (((crc >> 8) & 0xff) != pack[index++] ||
		((crc & 0xff) != pack[index++]))
	{
		DEBUG_STR("uaprot check crc2 err\r\n");
		return 0;
	}
	if (pack[index] == 0xA5)
		index++;

	para->bctl = bctl;
	para->port = port;
	para->dlen = dlen;

	return index;
}

/*****************************************************************************
 Prototype    : uaprot_set_gain
 Description  : uaprot set gain
 Input        : const uint8_t * buff  
                uint16_t size         
                uint16_t r            
                uint16_t g            
                uint16_t b            
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
int uaprot_set_gain(uint8_t * buff, uint16_t size, uint16_t r, uint16_t g, uint16_t b)
{
	if (buff == NULL || size < 8) {
		DEBUG_STR("uaprot_set_gain:para is err");
		return 0;
	}
	parse_word(&buff[0], r);
	parse_word(&buff[2], g);
	parse_word(&buff[4], b);
	parse_word(&buff[6], 0);

	return 8;
}

/*****************************************************************************
 Prototype    : uaprot_get_gain
 Description  : uaprot get gain
 Input        : const uint8_t * pack  
                uint16_t * pr         
                uint16_t * pg         
                uint16_t * pb         
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void uaprot_get_gain(const uint8_t * pack, uint16_t * pr, uint16_t * pg, uint16_t * pb)
{
	if (pack == NULL || pr == NULL || pg == NULL || pb == NULL) {
		DEBUG_STR("uaprot_get_gain:para is err");
		return ;
	}

	*pr = combo_word(&pack[0]);
	*pg = combo_word(&pack[2]);
	*pb = combo_word(&pack[4]);
}

/*****************************************************************************
 Prototype    : uaprot_set_class
 Description  : uaprot set class
 Input        : uint8_t * buff  
                uint32_t bkey   
                uint8_t eps     
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
int uaprot_set_class(uint8_t * buff, uint16_t size, uint16_t amount)
{
	if (buff == NULL || size < 8) {
		DEBUG_STR("uaprot_set_class:para is err");
		return 0;
	}
	uint32_t bkey = (amount & 0xFFF) | ((0x03 << 16) & 0x30000);
	parse_dword(&buff[0], bkey);
	buff[4] = 0x05;
	buff[5] = 0x06;
	buff[6] = 0;
	buff[7] = 0;

	return 8;
}

/*****************************************************************************
 Prototype    : uaprot_get_class
 Description  : uaprot get class
 Input        : const uint8_t * pack  
                uint32_t * bkey       
                uint8_t * eps         
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/16
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void uaprot_get_class(const uint8_t * pack, uint16_t * amount)
{
	if (pack == NULL || amount == NULL){
		DEBUG_STR("uaprot_get_class:para is err");
		return ;
	}
	uint8_t eps;
	uint32_t bkey;

	bkey = combo_dword(&pack[0]);
	eps = pack[4];
	eps = eps;
	*amount = bkey & 0xFFF;
}

